AI help for Corona SDK - artificial-intelligence

I've created a game which loops through a table of properties to create enemies to place on screen. The created enemies are stored in a variable called "baddie", and things like their x and y value are determined by the properties I gave them in the table. Currently, "baddie" creates 3 enemies at varying spots on screen. It looks something like this.
for i=1, #level[section]["enemies"] do
local object = level[section]["enemies"][i]
baddie = display.newSprite(baddieSheet, baddieData)
baddie.anchorX = 0.5
baddie.anchorY = 1
baddie.x = object["position"][1]; baddie.y = object["position"][2];
baddie.xScale = -1
baddie.myName = "Baddie"
baddie.health = 15
baddie:setSequence("standrt"); baddie:play()
physics.addBody(baddie, "dynamic", {radius=22, density=0.1, friction=10.0, bounce=0.0})
baddie.isFixedRotation = true
enemyGroup:insert(baddie)
end
I then inserted all of the created instances stored in the baddie variable, into a display group called "enemyGroup."
Now here's my question. I'm working on my game's AI and storing it all in an enterFrame listener. I want to make a "True/False" flag called "inRange." When the enemy's x position is within 20 pixels of the player's x, inRange = true. When it's true, the enemy will attack him. But I haven't figured out a way to make the inRange flag check for each individual enemy, instead of all of them.
I was thinking of something like,
for i = 1, enemyGroup.numChildren do
enemyGroup[i].widthBetween = enemyGroup[i].x - sprite.x
if enemyGroup[i].widthBetween <= 20 and enemyGroup[i].widthBetween >= -20 then
enemyGroup[i].inRange = true
else
enemyGroup[i].inRange = false
end
end
But the issue is, enemyGroup[i].inRange is a local value and I can't call for it in outside of the loop or in other functions. This is obviously problematic, because in another function I want to have each individual enemy punch, roll, jump, etc when their individual inRange property is true. Is there a way I can store enemyGroup[i].inRange so that I can call for it whenever?
Sorry if this question is confusing. It's been a struggle to word it.

I'm not sure why this isn't working for you. enemyGroup[i].inRange is not local, its an attribute of the object at enemyGroup[i]. It should be avalble anywhere you can access enemyGroup[i].
Personally I would have not used a display.newGroup() for this, instead I would have just created an array/table that's scoped for the whole scene.
local baddies = {}
then in your loop:
--enemyGroup:insert(baddie) instead of this, do this:
baddies[#baddies + 1] = baddie
Then you have a table that you can loop over, but it's really more code style than functionality. As long as your enemyGroup is scoped at a high enough level that any function that the scene can see.

you should create a file in the structure below:
module(..., package.seeall)
enemyGroup = {}
and in all your files where you want to use this table, first of all require this file( assume you named this file enemies.lua):
local enemiesArray = require "enemies"
-- somewhere in your code:
enemiesArray.enemyGroup[i].isRange = true -- or whatever you like to do
there is one better option for you to use _G variable. when you store an object to _G you can access that wherever you want( like the famous design pattern Singleton ). just set the variable one time and use it anywhere and as much as you want. for example:
-- in one file you set enemy table:
_G.enemies = enemyGroup
-- somewhere else in nowhere :)
print(_G.enemies.isRange)

Related

I want to create a 2D array of points that links to my 2D array of components

I am making a circuit diagram drawer for a school project and have a 2D array that stores whether 2 components are connected or not. I want to find a way to have an array that then stores the co-ordinates of these points so that if they are deleted, it can find the points and get rid of the connection
ElseIf P(1).X = Nothing And P(1).Y = Nothing Then
P(1).X = pointx
P(1).Y = pointy
Form1.Drawlines() 'run the DrawLines sub in Form1.vb
NoOfNodes = NoOfNodes + 1 'increment the NoOfNodes Variable by 1
Node2 = COMPONENTID
Connections(Node1, Node2) = true
This is the code that stores the points being drawn, at the end the value of Connections is set to true to show that there is a connection between the components.
I need a way to have another array that can say something along the lines of:
Connections(Node1,Node2) = (P(1),P(0))
any contribution is much appreciated,
Charlie
Sounds like each element in your array should point to an instance of a class. On the class you can pack as many attributes and as much information about the connection as you like.

Generating a reverse-engineerable code to save game, python 3

So I'm making a little text based game in Python and I decided for a save system I wanted to use the old "insert code" trick. The code needs to keep track of the players inventory (as well as other things, but the inventory is what I'm having trouble with).
So my thought process on this would be to tie each item and event in the game to a code. For example, the sword in your inventory would be stored as "123" or something unique like that.
So, for the code that would generate to save the game, imagine you have a sword and a shield in your inventory, and you were in the armory.
location(armory) = abc
sword = 123
shield = 456
When the player inputs the command to generate the code, I would expect an output something like:
abc.123.456
I think putting periods between items in the code would make it easier to distinguish one item from another when it comes to decoding the code.
Then, when the player starts the game back up and they input their code, I want that abc.123.456 to be translated back into your location being the armory and having a sword and shield in your inventory.
So there are a couple questions here:
How do I associate each inventory item with its respective code?
How do I generate the full code?
How do I decode it when the player loads back in?
I'm pretty damn new to Python and I'm really not sure how to even start going about this... Any help would be greatly appreciated, thanks!
So, if I get you correctly, you want to serialize info into a string which can't be "saved" but could be input in your program;
Using dots is not necessary, you can program your app to read your code without them.. this will save you a few caracters in lenght.
The more information your game needs to "save", the longer your code will be; I would suggest to use as short as possible strings.
Depending on the amount of locations, items, etc. you want to store in your save code: you may prefer longer or shorter options:
digits (0-9): will allow you to keep 10 names stored in 1 character each.
hexadecimal (0-9 + a-f, or 0-9 + a-F): will allow you to keep from 16 to 22 names (22 if you make your code case sensitive)
alphanum (0-9 + a-z, or 0-9 + a-Z): will allow you to keep from 36 to 62 names (62 if case sensitive)
more options are possible if you decide to use punctuation and punctuated characters, this example will not go there, you will need to cover that part yourself if you need.
For this example I'm gonna stick with digits as I'm not listing more than 10 items or locations.
You define each inventory item and each place as dictionaries, in your source code:
You can a use single line like I have done for places
places = {'armory':'0', 'home':'1', 'dungeon':'2'}
# below is the same dictionary but sorted by values for reversing.
rev_places = dict(map(reversed, places.items()))
Or for improved readability; use multiple lines:
items = {
'dagger':'0',
'sword':'1',
'shield':'2',
'helmet':'3',
'magic wand':'4'
}
#Below is the same but sorted by value for reversing.
rev_items = dict(map(reversed, items.items()))
Store numbers as strings, for easier understanding, also if you use hex or alphanum options it will be required.
Then also use dictionaries to manage in game information, below is just a sample of how you should represent your game infos that the code will produce or parse, this portion should not be in your source code, I have intentionally messed items order to test it.;
game_infos = {
'location':'armory',
'items':{
'slot1':'sword',
'slot2':'shield',
'slot3':'dagger',
'slot4':'helmet'
}
}
Then you could generate your save code with following function that reads your inventory and whereabouts like so:
def generate_code(game_infos):
''' This serializes the game information dictionary into a save
code. '''
location = places[game_infos['location']]
inventory = ''
#for every item in the inventory, add a new character to your save code.
for item in game_infos['items']:
inventory += items[game_infos['items'][item]]
return location + inventory # The string!
And the reading function, which uses the reverse dictionaries to decipher your save code.
def read_code(user_input):
''' This takes the user input and transforms it back to game data. '''
result = dict() # Let's start with an empty dictionary
# now let's make the user input more friendly to our eyes:
location = user_input[0]
items = user_input[1:]
result['location'] = rev_places[location] # just reading out from the table created earlier, we assign a new value to the dictionary location key.
result['items'] = dict() # now make another empty dictionary for the inventory.
# for each letter in the string of items, decode and assign to an inventory slot.
for pos in range(len(items)):
slot = 'slot' + str(pos)
item = rev_items[items[pos]]
result['items'][slot] = item
return result # Returns the decoded string as a new game infos file :-)
I recommend you play around with this working sample program, create a game_infos dictionary of your own with more items in inventory, add some places, etc.
You could even add some more lines/loops to your functions to manage hp or other fields your game will require.
Hope this helps and that you had not given up on this project!

loop over variables and years

I am trying to generate variables in the form varyear based on a list of original variables with random variable names. For example, based on the first variable E4252, I'll get a new variable called var2013; then var2011,
var2009, var2007 and so on to var1999.
Here is what I wrote, but didn't work:
local myvar "E4252 E5219 E4693 E4102 E2803 E2046 E1462 E1079"
local i = 2015
foreach x of myvar {
local i = `i' - 2
gen var`i' = `x'
}
You need to tell Stata that myvar is a local in your loop:
local myvar "E4252 E5219 E4693 E4102 E2803 E2046 E1462 E1079"
local i = 2015
foreach x of local myvar {
local i = `i' - 2
gen var`i' = `x'
}
Alternatively, you can refer the contents of the local directly:
foreach x in `myvar' {
...
}
Some alternatives to #Dimitriy's good answer.
For a short list of names like this, you can be direct and avoid a local macro. It's just an extra level of indirection.
Why generate at all? It sounds as if you are adopting a better set of variable names, so rename saves you having the same information repeated in two sets of variables.
I'd start with the first year used, i.e. 2013 not 2015.
local i = 2013
foreach x in E4252 E5219 E4693 E4102 E2803 E2046 E1462 E1079 {
rename `x' var`i'
local i = `i' - 2
}
You could just use rename all at once.
rename (E4252 E5219 E4693 E4102 E2803 E2046 E1462 E1079) (var2013 var2011 var2009 var2007 var2005 var2003 var2001 var1999)
There is a simple trade-off here.
The last code example is simple and direct and it's easy to see at a glance what has been done.
But if you don't play with loops, you never learn good technique.
I wouldn't want to type out any (much) longer list of names, but people are going to have different thresholds here. Also, you may have other problems of the same type, which makes mastering loop technique more important.

How to make a function wait X amount of time in LUA (Love2d)?

I am very new to programming and coming from a "custom map" background in games like SC2. I am currently trying to make a platformer game in Love2d. But I wonder how I can make something wait X amount of seconds before doing the next thing.
Say I want to make the protagonist immortal for 5 seconds, how should that code look like ?
Immortal = true
????????????????
Immortal = false
As I have understood there is no built in wait in Lua nor Love2d.
It sounds like you're interested in a temporary state for one of your game entities. This is pretty common - a powerup lasts for six seconds, an enemy is stunned for two seconds, your character looks different while jumping, etc. A temporary state is different than waiting. Waiting suggests that absolutely nothing else happens during your five seconds of immortality. It sounds like you want the game to continue as normal, but with an immortal protagonist for five seconds.
Consider using a "time remaining" variable versus a boolean to represent temporary states. For example:
local protagonist = {
-- This is the amount of immortality remaining, in seconds
immortalityRemaining = 0,
health = 100
}
-- Then, imagine grabbing an immortality powerup somewhere in the game.
-- Simply set immortalityRemaining to the desired length of immortality.
function protagonistGrabbedImmortalityPowerup()
protagonist.immortalityRemaining = 5
end
-- You then shave off a little bit of the remaining time during each love.update
-- Remember, dt is the time passed since the last update.
function love.update(dt)
protagonist.immortalityRemaining = protagonist.immortalityRemaining - dt
end
-- When resolving damage to your protagonist, consider immortalityRemaining
function applyDamageToProtagonist(damage)
if protagonist.immortalityRemaining <= 0 then
protagonist.health = protagonist.health - damage
end
end
Be careful with concepts like wait and timer. They typically refer to managing threads. In a game with many moving parts, it's often easier and more predictable to manage things without threads. When possible, treat your game like a giant state machine versus synchronizing work between threads. If threads are absolutely necessary, Löve does offer them in its love.thread module.
I normally use cron.lua for what you're talking about: https://github.com/kikito/cron.lua
Immortal = true
immortalTimer = cron.after(5, function()
Immortal = false
end)
and then just stick immortalTimer:update(dt) in your love.update.
You could do this:
function delay_s(delay)
delay = delay or 1
local time_to = os.time() + delay
while os.time() < time_to do end
end
Then you can just do:
Immortal == true
delay_s(5)
Immortal == false
Of course, it'll prevent you from doing anything else unless you run it in its own thread. But this is strictly Lua as I know nothing of Love2d, unfortunately.
I reccomend that you use hump.timer in your game,like this:
function love.load()
timer=require'hump.timer'
Immortal=true
timer.after(1,function()
Immortal=false
end)
end
instead of using timer.after,you can also use timer.script,like this:
function love.load
timer=require'hump.timer'
timer.script(function(wait)
Immortal=true
wait(5)
Immortal=false
end)
end
don't forget to add timer.updateinto function love.update!
function love.update(dt)
timer.update(dt)
end
hope this helped ;)
Download link:https://github.com/vrld/hump

flex 3: Can anybody help me optimize this array -> arrayCollection function?

I'm using a parent to pass a multi-dimensional array to a child. Structure of the array, named projectPositions is as follows (with example data):
projectPositions[0][0] = 1;
projectPositions[0][1] = 5;
projectPositions[0][2] = '1AD';
projectPositions[0][3] = 'User name';
I need to take this inherited array and turn it into an arrayCollection so that I can use it as a dataProvider. Currently, my init function (which runs onCreationComplete) has this code in it to handle this task of array -> arrayCollection:
for (var i:int = 0; i < projectPositions.length; i++)
{
tempObject = new Object;
tempObject.startOffset = projectPositions[i][0];
tempObject.numDays = projectPositions[i][1];
tempObject.role = projectPositions[i][2];
tempObject.student = projectPositions[i][3];
positionsAC.addItemAt(tempObject, positionsAC.length);
}
Then, during a repeater, I use positionsAC as the dataprovider and reference the items in the following way:
<mx:Repeater id="indPositions" dataProvider="{positionsAC}" startingIndex="0" count="{projectPositions.length}">
<components:block id="thisBlock" offSet="{indPositions.currentItem.startOffset}" numDays="{indPositions.currentItem.numDays}" position="{indPositions.currentItem.role}" sName="{indPositions.currentItem.student}" />
</mx:Repeater>
This all works fine and returns the desired effect, but the load time of this application is around 10 seconds. I'm 99% sure that the load time is caused by the array -> arrayCollection for loop. Is there an easier way to achieve the desired effect without having to wait so long for the page to load?
The issue your having loading items could be because you are using a repeater instead of a list class.
With a repeater, there will be a block created in memory, and drawn on the screen. So, if you have 100 items in your array, then 100 blocks will be created. this could slow down both initial creation and the overall app.
A list based class focuses on a technique called renderer recycling; which means only the displayed elements are created and rendered on the screen. So, depending on settings, you'd usually have 7-10 'block' instances on the screen, no matter how many items you have in your array.
change
positionsAC.addItemAt(tempObject, positionsAC.length);
to
positionsAC.addItem(tempObject);
addItemAt is causing a reindex of the collection which can greatly slow down the collection.
[EDIT]
Put this trace statement before and after the loop
take the output and subtract one from the other and that will show how many milliseconds the loop has run.
var date:Date = new Date( );
trace( date.getTime())

Resources