Creature Corp - Movie Game Contest Entry

Started by Derron, March 14, 2018, 14:07:38

Previous topic - Next topic

iWasAdam

#60
Linux Mint Sylvia 64 xfrce
Right I'll see if I can get it working....

linux mint -check
install -check
get monkey2 1.05 -check
do strange sudo installs - check
begin rebuildall from monkey2 - check.....!!!!!!!

Good Lard... It's compiling!!!!!!
I've tried 4 different linux configurations, and numerous forum posts and still couldn't get anything to work.
This is the first time I've got this far....!

HOLY CRAP!!!!!! IT WORKS


Qube

Quote from: Derron on April 17, 2018, 11:51:22
@ Qube
So I assume the whole thing is more or less a single file project (with "includes" rather than "imports") with all "objects" seeing each other? I think it is a bit of a pity that AGK does not over "lite OOP" like BlitzMax. Am not sure how complicate/troublesome/tricky bigger projects get without proper encapsulation. Regarding GUI: I am not talking about simple buttons. My GUI has accordeons,  dropdown/comboboxes, customizable tooltips, modal widgets, textareas, sliders, lists, versatile scrollbars, drag'n'drop, layers/limits, event system ... and uses nine patches, content padding, bitmap fonts (also talking about text wrapping, text-formatting support), ... Things can get pretty "complex" (or at least "heavy") once you need more and more features and widget kinds. But yes, Buttons, checkboxes, simple "state machines" (radio buttons, ...) are done pretty quick. Handling modal dialogues etc. can be done procedurally ("if gameMenuIsShown then...") but it would be nice if it was done at least semi-automatically.
If there is no much GUI/HUD-stuff to do then one could do it that way, but the more options you provide to the player, the more you benefit from "automatization".
Yes, you can split up your code and call it via includes ( or Insert as AGK calls it ). Coding big projects isn't an issue at all plus OOP is just another way of working to which I've never come across any game that couldn't be done without OOP. Neat code wins every time :)

I've written the more complex GUI's too, with Windows, buttons, sliders, radio buttons, list boxes, drop down menus, popup menus etc etc. I just find them incredibly boring to code :(

Quote from: Derron on April 17, 2018, 11:51:22
@ game
So gameplay would be single player or would you plan to have kind of "cities" consisting of multiple stores fighting for a limited amount of customers, stock supply ...? So no need to render the other stores - just synchronizing "numbers" and people "moods".
I aways envisaged it as a single player game and as far as the game is concerned there are no other stores. I think having other stores you are fighting with could work out but I would be hesitant to have that a a big side to the game.
Mac Studio M1 Max ( 10 core CPU - 24 core GPU ), 32GB LPDDR5, 512GB SSD,
Beelink SER7 Mini Gaming PC, Ryzen 7 7840HS 8-Core 16-Thread 5.1GHz Processor, 32G DDR5 RAM 1T PCIe 4.0 SSD
MSI MEG 342C 34" QD-OLED Monitor

Until the next time.

Qube

Quote from: iWasAdam on April 17, 2018, 14:45:01
Linux Mint Sylvia 64 xfrce
Right I'll see if I can get it working....

linux mint -check
install -check
get monkey2 1.05 -check
do strange sudo installs - check
begin rebuildall from monkey2 - check.....!!!!!!!

Good Lard... It's compiling!!!!!!
I've tried 4 different linux configurations, and numerous forum posts and still couldn't get anything to work.
This is the first time I've got this far....!

HOLY CRAP!!!!!! IT WORKS

AGK, download, install go - on Windows, Mac & Linux. Simples ;D - Why torture yourself :o

( thread derail over )
Mac Studio M1 Max ( 10 core CPU - 24 core GPU ), 32GB LPDDR5, 512GB SSD,
Beelink SER7 Mini Gaming PC, Ryzen 7 7840HS 8-Core 16-Thread 5.1GHz Processor, 32G DDR5 RAM 1T PCIe 4.0 SSD
MSI MEG 342C 34" QD-OLED Monitor

Until the next time.

Derron

#63
As Adam suggested some kind of "sketch" (ascii gfx):
How would you tackle to disconnect "units" from "persons". For now I have persons - which are non-graphical and contain properties like "nameFamily:string", "wage:int", "hiredTime:Long" and corresponding methods ("CalculateWage()", "GetWage()" ...)... These "persons" do know to which production device they are currently assigned to (via "productionDeviceGUID", so only a weak reference). I also store actions/tasks (going to spawn point, search new production device, working at a device, idling, ... finite state machine).

Then I have added some methods to these persons which are called by the game: onReachTarget(params), onAssigntoProductionDevice(params) ...

The visual representation is done by a "TileEntityUnit" class which holds a reference to the person (could be accessible via personGUID too...). It knows the target on the tile map - and does the movement and rendering. For now it also handles action/task updates when reaching positions/targets - or if "inbetween checks" show that a target is no longer valid (eg. someone else is using it now, or the target got sold/ path blocked). I know this could be done via events too (persons list if other persons use a device now and stop their task then).

The "person" class (and other "game objects") do not know about their tilemap representation - I try to encapsulate as much as possible to avoid circular dependencies (and potential memory leaks).


Ok, so the visual representation interfers with / controls behaviour of the person class - which is what I worry about. It feels like a "dirty hack".

So normally I would think that "person" should know where it goes to ("target position" or "target object") and how long the route will take (in "game time" - so it allows various game speeds, like I already added with keys 1-4). The "TTileEntityUnit" would just represent the visual state and should in no way be required to modify "person"-properties.

In other words: how to bring together "tilemap" (iso or top-down does not matter) and "non-tilemap-objects": in other words, how would you make it "client-less"/"head-less"?



bye
Ron

Qube

It looks like you're overcomplicating things :o

Very roughly and cutdown, I'd just define things like so ( using wacky AGK code :P ) :


Type tPerson
id
name
wage
hiredTime
jobTitle
currentAction
xTile
yTile
EndType

Type tDevice
id
name
currentState
hasPerson
xTile
yTile
EndType


Then you can easily parse through each person to update them, see what they are doing etc and just as easily parse though devices to see what state they are in, if any person is at them.

I think going OO nuts is not the right or easiest approach.

Same with game speed. If you code it for a target frame rate of 60FPS and assume that is normal speed then it's easy to speed up the game based off deltaTime. The speed of characters walking, the time, time it takes for a task to complete can all be linked very easily.
Mac Studio M1 Max ( 10 core CPU - 24 core GPU ), 32GB LPDDR5, 512GB SSD,
Beelink SER7 Mini Gaming PC, Ryzen 7 7840HS 8-Core 16-Thread 5.1GHz Processor, 32G DDR5 RAM 1T PCIe 4.0 SSD
MSI MEG 342C 34" QD-OLED Monitor

Until the next time.

Derron

BTW my person type looks like this for now:

Code (BlitzMax) Select

Type TPersonBase extends TEntityBase
Field lastName:String = ""
Field firstName:String = ""
Field nickName:String = ""
Field gender:int
Field countryCode:string = "US"

'wage + modifier (more expensive at same skills)
Field wageMod:Float = 1.0
Field wageBase:int = 0
Field wage:int = 0
'paid for todays work?
Field wagePaid:int = False

'reputation a company has to have before applying for a job
Field reputationMinimum:Int = 0

'when born?
Field timeDOB:Long
'when hired?
Field timeHired:Long = -1
Field hired:int = False
'got fired meanwhile?
Field timeFired:Long = -1
Field fired:int = False
'individual skill values
Field skillLevels:int[]
'how many times a skill was used (for level ups)
Field skillsUsed:int[]

'what skill was used for last production point
Field lastProductionPointSkillType:int
'when was the last skill point created?
Field lastProductionPointCreationTime:Long

'influencing productivity of that person
Field productivityMod:Float = 1.0

Field assignedProductionDevice:TProductionDevice
Field assignedProductionDeviceTime:Long
Field assignedProduction:TProduction
Field assignedProductionTime:Long

Field actionState:int = 0
Field actionStateTime:Long = -1
Field actionStateWorldTime:Long = -1
Field nextActionStateWorldTime:Long = -1
Field currentTask:int = TPersonTasks.NONE
Field currentTaskTime:Long = -1
Field currentTaskWorldTime:Long = -1

'energy
Field energyRecoverAt:Int = 50000
Field energyRecoverTo:Int = 60000
Field energyRecoverLevel:Int = 0
Field energy:Int = 100000
Field energyMax:Int = 100000
Field energyUseMod:Float = 1.0
Field energyRecoverMod:Float = 1.0
Field energyUpdateIntervalMod:Float = 1.0
Field lastEnergyUpdateTime:Long

'working times
Field workStartHour:int = 8
Field workEndHour:int = 16
Field workHours:int = 9 'including break
Field workShift:int = 0 '0 early, 1 = mid, 2 = evening, 3 = night
Field workShiftsUnwanted:int[]
'ATTENTION: for now you can simply cheat employees into working more
'           by changing their shift :-)
'TODO: Save new SetShifts() into other variables and when
'      a current shift is planned to start this new shift values are
'      copied to the real used variables and time is checked again

Global skillsUsedLevelUps:int[] = [10, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000]
Const energyRecoverLevelMax:Int = 3
[...]

(yes, getting fired is something else than setting "hired to false")


What you do is adding things like "tile position" to the person/device - something they normally should not know about (or even care about) - separation of concerns. But as "xTile" and "yTile" are simple integer values, I think that's "ok" to make things easier. And yes, I thought about that too (main idea is always to allow "separation" to avoid circular depencies - so no tileX=TTileobject but tileX=102)

Ok, so "TPerson" now is able to know where it is located on a map (xTile,yTile). Moving to another object would need to go about an object "controlling everything": "world.GoTo(person, xTile+10, yTile)" or so. Why? A person should be able to target items (but of course should not need to know that it is "on a map" - so it just needs to say: please go to the item). It also should not know about "TDevice" as "TDevice" knows about "TPerson" already - I normally create some base classes for that (TPersonBase, TDeviceBase) which could get used by the other classes. These base classes only contain "encapsulated" data or base data (int, float, string, list). As said, to avoid circular dependency. In the base class I could have things like "GetAssignedPersons:TList()" which returns nothing in the base class, but a real list of person(base) in the "TDevice" class. In C/C++ you would surely use "interfaces" for this, but BMX(vanilla) does not have this, so I am used to use these to keep vanilla compatibility.

I am aware that many problems are "self-made" as it over-complicates stuff. I could just have TPerson and TDevice in the same file and they could happily access each others properties. But for me this does not look "clean" - while of course it cuts down development time and eases a lot of pain. In AGK this will work that way as there are only "includes" (so they are "in one file" already - somehow). With "includes" the whole thing is a lot of easier to code but I am not sure how AGK (or others) do the Garbage Collection then.

I should really do not care much about "reusability" (I always think one could use a class in another scenario - so encapsulation makes this pretty easy).
Also I always try to think of objects using "natural thoughts". A person does say: "I want to go to the computer", it does not think "I want to go to the computer which is located at the left corner of my office". So the persons in the game should not care for tilemaps - they just need to know that the computer exists, and if they are at it or not - and that they could go to it, or not ("already occupied"). Maybe doing it that way is overcomplication - similar to having total "normalization" in Database schemes - sometimes having "dirty" DB-structures helps speeding up things (adding indices to remove some queries and so on). Hmm should really try to "keep my code dirty" :-).


Let's also check what Adam suggests - how he would tackle such things (he seems to be a "procedural guy" too - albeit using Monkey2).



@ Game
If you want to code something in your evenings: feel free to use the assets of my game as place holders so you do not need to stare at rectangles or such a thing.


also here is a simple iso-rectangle / iso-block code for prototyping - might save you 3-4 minutes of thinking about it:
Code (BlitzMax) Select

Function DrawIsoRect(x:Float,y:Float,w:Float,h:float, filled:int = True)
if filled
DrawPoly([x, y + 0.5*h, x + 0.5*w, y, x + w, y + 0.5*h, x + 0.5*w, y + h])
else
DrawLine(x, y + 0.5*h, x + 0.5*w, y)
DrawLine(x + 0.5*w, y, x + w, y + 0.5*h)
DrawLine(x + w, y + 0.5*h, x + 0.5*w, y + h)
DrawLine(x + 0.5*w, y + h, x, y + 0.5*h)
endif
End Function


Function DrawDemoBlock(x:Float,y:Float, height:int, tileWidth:int, tileHeight:int)
height :+ tileHeight
if height > tileHeight
local oldCol:TColor = new TColor.Get()

oldCol.Copy().AdjustBrightness(-0.2).SetRGB()
DrawIsoRect(x,y, 2*tileWidth, tileHeight, True)
DrawRect(x,y - height + 1.5*tileHeight, 2*tileWidth, height-tileHeight)

oldCol.SetRGB()
DrawLine(x + tileWidth, y + 2*tileHeight - height, x + tileWidth, y + tileHeight-1)
DrawIsoRect(x,y - (height-tileHeight), 2*tileWidth, tileHeight, True)
else
DrawIsoRect(x,y - (height-tileHeight), 2*tileWidth, tileHeight, True)
endif
End Function


bye
Ron

Qube

QuoteI am aware that many problems are "self-made" as it over-complicates stuff. I could just have TPerson and TDevice in the same file and they could happily access each others properties. But for me this does not look "clean" - while of course it cuts down development time and eases a lot of pain. In AGK this will work that way as there are only "includes" (so they are "in one file" already - somehow). With "includes" the whole thing is a lot of easier to code but I am not sure how AGK (or others) do the Garbage Collection then.
I think the main thing is to code in the style you are most comfortable with. There is no right or wrong way, just the final result. No idea how garbage collection is handed in AGK, it's not anything I worry about.
Mac Studio M1 Max ( 10 core CPU - 24 core GPU ), 32GB LPDDR5, 512GB SSD,
Beelink SER7 Mini Gaming PC, Ryzen 7 7840HS 8-Core 16-Thread 5.1GHz Processor, 32G DDR5 RAM 1T PCIe 4.0 SSD
MSI MEG 342C 34" QD-OLED Monitor

Until the next time.

Derron

Lunch break and I reorganized my blender files ... some "offsets" were not clear to me (only happening in the file linking to an asset) - I just parented that stuff to new empties so I rotate/position the "empty" then.



Also created some "target empties" so the script knows to where it has to move stuff - which allows adjustments without altering the script then.


bye
Ron